package com.findme.unvelouse.facade;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.TreeMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import android.location.Location;
import android.util.Log;

import com.findme.unvelouse.bo.VeloStation;
import com.google.android.maps.GeoPoint;

public class VeloStationFacade {

	private static List<VeloStation> mVeloStations = null;

	/**
	 * Populate the veloStation list from cvs file
	 * 
	 * @param inputStream
	 *            csv file containing data
	 */
	public static void populate(InputStream inputStream) {

		try {

			if (mVeloStations == null) {

				// create BufferedReader to read csv file
				BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
				String strLine = "";
				int lineNumber = 0;

				List<VeloStation> temporayVeloStationList = new ArrayList<VeloStation>();

				// read comma separated file line by line
				while ((strLine = br.readLine()) != null) {
					if (lineNumber > 0) {

						// process the line, stuff to List
						String[] values = strLine.split(";");

						VeloStation veloStation = new VeloStation();

						veloStation.setName(values[0]);
						veloStation.setCity(values[9]);
						veloStation.setDirectorWord(values[6]);
						veloStation.setOriginalNbBorne(Integer.parseInt(values[2]));
						veloStation.setNoStation(Integer.parseInt(values[1]));
						veloStation.setNoStreet(values[7]);
						veloStation.setStreet(values[5]);
						veloStation.setGeoPoint(newGeoPoint(Float.parseFloat(values[14].replace(',', '.')),
								Float.parseFloat(values[13].replace(',', '.'))));

						temporayVeloStationList.add(veloStation);

					}
					lineNumber++;

				}

				mVeloStations = temporayVeloStationList;
			}

		} catch (Exception e) {
			System.out.println("Exception while reading csv file: " + e);
		}

	}

	/**
	 * @param geoPoint
	 * @param nbStations
	 * @return list of the nbStations Stations nearest to geoPoint
	 */
	public List<VeloStation> findVeloStationAround(GeoPoint geoPoint, int nbStations) {

		List<VeloStation> nearestVeloStation = new ArrayList<VeloStation>();

		HashMap<VeloStation, Float> distanceVeloStation = new HashMap<VeloStation, Float>();

		Location originLocation = new Location("centerPoint");
		originLocation.setLatitude(geoPoint.getLatitudeE6() / 1E6);
		originLocation.setLongitude(geoPoint.getLongitudeE6() / 1E6);

		for (VeloStation v : mVeloStations) {

			Location l = new Location(v.getName());
			l.setLatitude(v.getGeoPoint().getLatitudeE6() / 1E6);
			l.setLongitude(v.getGeoPoint().getLongitudeE6() / 1E6);

			float currentDistance = originLocation.distanceTo(l);
			distanceVeloStation.put(v, currentDistance);
		}

		ValueComparator comparator = new ValueComparator(distanceVeloStation);
		TreeMap<VeloStation, Float> sortedDistanceVeloStation = new TreeMap<VeloStation, Float>(comparator);

		sortedDistanceVeloStation.putAll(distanceVeloStation);

		int index = 0;
		for (VeloStation v : sortedDistanceVeloStation.keySet()) {
			if (index < nbStations) {
				nearestVeloStation.add(v);
			}
			index++;
		}

		return nearestVeloStation;
	}

	public static GeoPoint newGeoPoint(float lat, float lng) {
		return new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6));
	}

	public static List<VeloStation> getAllVeloStation() {
		return mVeloStations;
	}

	class ValueComparator implements Comparator {

		HashMap<VeloStation, Float> map;

		public ValueComparator(HashMap<VeloStation, Float> base) {
			this.map = base;
		}

		@Override
		public int compare(Object a, Object b) {

			if (map.get(a) > map.get(b)) {
				return 1;
			} else if (map.get(a) == map.get(b)) {
				return 0;
			} else {
				return -1;
			}
		}
	}

	public VeloStation getVeloStationById(int stationIndex) {

		for (VeloStation v : mVeloStations) {
			if (v.getNoStation().equals(stationIndex)) {
				return v;
			}
		}

		return null;
	}

	/**
	 * Update the number of bike available / empty space available and total
	 * space
	 * 
	 * @param veloStation
	 */
	public void updateAvailability(VeloStation veloStation) {

		Integer nbBikeAvailable = null;
		Integer nbPlaceAvailable = null;
		Integer nbTotalBorne = null;

		URL veloToulouseUrl;
		try {
			veloToulouseUrl = new URL("http://www.velo.toulouse.fr/service/stationdetails/toulouse/" + veloStation.getNoStation());

			URLConnection yc = veloToulouseUrl.openConnection();

			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(yc.getInputStream()/* xmlResponse */);
			doc.getDocumentElement().normalize();

			Node available = (((Element) doc.getElementsByTagName("available").item(0)).getChildNodes().item(0));
			Node free = (((Element) doc.getElementsByTagName("free").item(0)).getChildNodes().item(0));
			Node total = (((Element) doc.getElementsByTagName("total").item(0)).getChildNodes().item(0));

			nbBikeAvailable = Integer.parseInt(available.getNodeValue());
			nbPlaceAvailable = Integer.parseInt(free.getNodeValue());
			nbTotalBorne = Integer.parseInt(total.getNodeValue());

		} catch (MalformedURLException e) {
			Log.e("FindMeUnVelouse", e.getLocalizedMessage());
			// continue
		} catch (IOException e) {
			Log.e("FindMeUnVelouse", e.getLocalizedMessage());
			// continue
		} catch (ParserConfigurationException e) {
			Log.e("FindMeUnVelouse", e.getLocalizedMessage());
			// continue
		} catch (SAXException e) {
			Log.e("FindMeUnVelouse", e.getLocalizedMessage());
			// continue
		}

		veloStation.setNbBikeAvailable(nbBikeAvailable);
		veloStation.setNbPlaceAvailable(nbPlaceAvailable);
		veloStation.setNbTotalBorne(nbTotalBorne);

	}

	/**
	 * set favoris on VeloStation reading string 1;25;53;2;8
	 * */
	public void updateFavoris(String favoriString) {

		String[] favoris = favoriString.split(";");

		for (int i = 0; i < favoris.length; i++) {

			String noStation = favoris[i];

			try {
				VeloStation v = this.getVeloStationById(Integer.parseInt(noStation));
				v.setFavori(true);
			} catch (NumberFormatException e) {
				// we do not set as favorite if parse exception
				// log.d("VeloStationFacade", e.get)
			}
		}

	}

	/**
	 * 
	 * @return list of favoris
	 */
	public List<VeloStation> getVeloStationFavoris() {

		List<VeloStation> favoris = new ArrayList<VeloStation>();

		for (VeloStation veloStation : mVeloStations) {
			if (veloStation.isFavori()) {
				favoris.add(veloStation);
			}
		}

		return favoris;
	}

	/**
	 * @return string which represents all favoris station
	 */
	public String getFavorisStringStream() {

		String favorisString = "";

		for (VeloStation veloStation : mVeloStations) {
			if (veloStation.isFavori()) {
				favorisString += veloStation.getNoStation() + ";";
			}
		}

		return favorisString;
	}
}
